
var m_data = {

	/**
	 * 加载其它 Script
	 * @since 0.2.0
	 */
	load : function(path) {
		requirejs.config({
			baseUrl: path
		});
		
		return new Promise(function (resolve, reject) {
			requirejs(['aframe/module', 'aframe/scene', 'aframe/asset', 'aframe/config', 'aframe/illustrate'],
					function () {
						resolve();
					},
					function () {
						reject();
					}
			);
		});
	},

	/**
	 * 加载 AFrame 前端框架
	 * @param path
	 *   aframe 所属的文件的位置. 为 null 是前端测试时使用, 启动服务器后不应该输入 null.
	 * @returns
	 *   Promise 对象, 加载完成之后的造作
	 * @since 0.2.0
	 */
	init: function(path) {
		if (path == null) {
			path = "../js";
		}
		
		return m_data.load(path);
	},
	
	/*
	 * 当前模块
	 * 放在这里就为了好拿
	 */
	curModule: null,

	/*
	 * 当前场景的引用, 指向上面 s.scenes 的某个元素, 或者 null
	 * 放在这里就为了好拿
	 */
	curScene: null,
	
	/*
	 * 每次 render 函数的调用函数列表, 以名称 - 函数指针的包装 Object 的形式存储
	 * 每个元素:
	 * {
	 *   "func": ... // Function, 执行入口函数
	 *   "module": ... // Object, 对应的模块. 可能多个 render 函数对应一个相同的模块
	 *   "opt": ... // Object, 参数
	 *   "count": ... // Integer, 已调用的次数
	 *   "baseTime": ... // Integer, 加入到 render 列表时的时间戳
	 *   "args": ... // 任意类型, 执行 func 的输入参数
	 * }
	 */
	renderFuncs: {},

	/**
	 * 现在的时间戳, 毫秒
	 */
	curTime: 0,

	/*
	 * render 函数的调用次数
	 */
	renderCount: 0,

	/*
	 * 共享数据上下文
	 */
	shareContext: {},

	/*
	 * 函数, 用于发送展示屏播放状态
	 */
	fSendStatus: null,
	
	/*
	 * 函数, 用于获取资源参数
	 * @param1 object
	 * {
	 *   type: <type>,
	 *   name: <name>
	 * }
	 * @param2 function(data)
	 *   完成查询之后的回调函数, data 是服务器返回的数据, object 格式
	 * @return 无
	 */
	fRequireAssets: null,

	/*
	 * 默认的渲染函数参数
	 */
	defRenderOpt : {
		// Boolean, 是否只运行这个渲染函数一次
		once : false,
		// Integer, 第一次运行渲染函数在多久之后, 单位毫秒
		delay : 0,
		// Integer, 每次函数的运行距离上一次的时间, 单位毫秒
		//	默认 -1, 即每一帧都执行.
		//	仅在上面 once = false 时有效
		interval : -1,
	},

	start: function() {
		this.m.scanModulesOrder();
		
		// v0.2.0 检查 require
		m_data.m.foreach(function(module) {
			m_data.a.requireAssetInModule(module);
		});
		
		this.m.stage = 2;
		m_data.e.release("start", null);
	},

	/**
	 * 每帧执行的流程
	 */
	render: function() {
		if (m_data.m.stage == 3) {
			return; // 全部播放完成
		}

		m_data.renderCount ++;
		var curTime = m_data.curTime = new Date().getTime();

		if (m_data.s.isCurSceneFin()) {
			// 在渲染函数列表中删除所有属于该场景的渲染函数
			for (index in m_data.renderFuncs) {
				delete m_data.renderFuncs[index];
			}

			// 开始执行场景的入口函数
			if (m_data.s.switchScene()) {
				m_data.s.play();
			} else {
				if (m_data.m.curModuleIdx >= 0) {
					m_data.e.release("module-complete", {
						index: m_data.m.curModuleIdx
					});
				}

				// 需要切换模块
				while (true) {
					if (m_data.m.switchModule()) {
						if (m_data.s.switchScene()) {
							m_data.s.play();
							break;
						}
					} else {
						console.log("所有场景播放结束");
						m_data.e.release("all-complete", null);
						m_data.sendCompleteStatus();
						return;
					}
				}
			}
		} else {
			m_data.s.curSceneCount ++;
			m_data.s.timestamp.duration = curTime - m_data.s.timestamp.base;
		}

		// render 列表部分
		
		for (name in m_data.renderFuncs) {
			var obj = m_data.renderFuncs[name];
			var opt = obj.opt;

			var offset = curTime - obj.baseTime;
			var needCall = false; // Boolean

			if (offset < opt.delay) {
				continue;
			} else {
				if (obj.count == 0) {
					needCall = true;
				} else if (opt.interval == -1) {
					needCall = true;
				} else if ((offset + opt.delay) / opt.interval >= obj.count) {
					needCall = true;
				}
			}

			if (needCall) {
				obj.func.call(obj.module, obj.args);
				obj.count++;
				if (opt.once) {
					delete m_data.renderFuncs[name]; // delete obj 是错误的
				}
			}
		}

	},
	
	/**
	 * 检查 config 是否为 null, 并给 config 添加 key-value 键值对
	 * @param module   
	 *   string, 模块名
	 * @param key
	 *   string, 存入模块的数据的键
	 * @param value
	 *   任意类型, 存入模块的数据的值，key与value为键值对
	 */
	judgeConfig: function(module,key,value){
		if(m_data.m.modules[module].config == null){
			m_data.m.modules[module].config = {};
		}
		m_data.m.modules[module].config[key] = value;
	},

	/**
	 * 向服务器端发送所有场景播放完成的消息
	 */
	sendCompleteStatus: function() {
		if (m_data.fSendStatus != null) {
			m_data.fSendStatus({
				status : "play-complete"
			});
		}
	},

	/**
	 * 订阅发布部分
	 */
	e: {

		/**
		 * 事件列表
		 * 里面每一个参数都是 Array(Function)
		 */
		events: {},

		/**
		 * 注册监听的事件
		 * @param event  String|Array(String)
		 *  想要接受的事件类型
		 * @param callback  Function(event, argv)
		 *  回调函数
		 */
		subscribe: function(event, callback) {
			if (typeof event == 'string') {
				this.subscribeOne(event, callback);
			} else if (event instanceof Array) {
				var len = event.length;
				for (var i = 0; i < len; i++) {
					this.subscribe(event[i], callback);
				}
			}
		},

		/**
		 * 注册一个监听的事件
		 * @param event  String
		 *  想要接受的事件类型
		 * @param callback  Function(event, argv)
		 *  回调函数
		 */
		subscribeOne: function(event, callback) {
			var funcs = this.events[event];
			if (funcs == null) {
				funcs = [];
				this.events[event] = funcs;
			}

			funcs.push(callback);
		},

		/**
		 * 发布事件
		 * @param event  String
		 *   事件名称
		 * @param argv  任意
		 *   其它附属参数
		 */
		release: function(event, argv) {
			var funcs = this.events[event];
			if (funcs == null) {
				return;
			}

			var len = funcs.length;
			for (var i = 0; i < len; i++) {
				funcs[i](event, argv);
			}
		}

	}

}

/**
 * 启动 aframe
 */
function startRender() {
	m_data.start();

	console.log("初始化结束");
	setInterval(m_data.render, 10); // 100 fps
}

/**
 * 添加场景或子场景的入口函数列表
 * @param name
 *   String, 场景或子场景的名称
 * @param func
 *   Function, 执行入口函数
 * @param module
 *   String, 属于哪个模块. 这个值现在不可以为 null
 * @param args
 *   任意类型, 可选, 执行该场景或子场景需要用到的数据, 自己定义
 * }
 */
function addSceneFunc(name, func, module, args) {
	name = String(name);
	if (typeof module !== 'string'){
		console.error('It is not a String');
		return;
	}

	if (typeof func !== 'function'){
		console.error('It is not a function');
		return;
	}

	m_data.s.scenes.push({
		name : name,
		func : func,
		module : module,
		args : args
	});

}

/**
 * 添加可执行函数, 将函数加入到渲染函数列表中 (m_data.renderFuncs).
 * 这些可执行函数将根据所给的参数 (opt)
 * 来确定之后在什么时候执行, 以什么方式执行
 * 
 * 初始化结束后, 就会每帧调用一次渲染函数列表中的所有函数.
 *
 * -----
 * 举例 1:
 * addRenderFunc('a', function() {
 * 	  ...
 * }, {once: true, delay: 1000});
 * 表示 1000 毫秒之后, 执行 function 里面的方法, 只执行一次
 *
 * -----
 * 举例 2:
 * addRenderFunc('a', func, {once: true, delay: 1000}, opt);
 * 表示 1000 毫秒之后, 执行 func(opt) 方法, 只执行一次
 * opt 将作为 func 的输入参数, 执行
 *
 * 
 * @param name
 *   String, 指示这个函数的键值.
 *   后面根据这个 key 能够定位到这个渲染函数, 决定是删除还是其它什么事情
 * @param func
 *   渲染函数
 * @param opt
 *   Object, 其它选项. 选项参数请参看上面的 m_data.defRenderOpt.
 * @param args
 *   任意类型, 可选, 用于后面传入到 render 作为输入的数据.
 */
function addRenderFunc(name, func, opt, args) {
	name = String(name);
	if(typeof func !== 'function'){
		console.error('It is not a function');
		return;
	}

	if (!opt) {
		opt = m_data.defRenderOpt;
	} else {
		opt.once = opt.once || m_data.defRenderOpt.once;
		if (opt.delay < 0) {
			opt.delay = m_data.defRenderOpt.delay;
		} else {
			opt.delay = opt.delay || m_data.defRenderOpt.delay;
		}
		opt.interval = opt.interval || m_data.defRenderOpt.interval;
	}

	m_data.renderFuncs[name] = {
		func : func,
		module : currentModule(),
		opt : opt,
		count : 0,
		baseTime : new Date().getTime(),
		args : args,
	};
}

/**
 * 告诉系统该场景或子场景已经播放完成了.
 */
function endScene() {
	console.log("场景 " + m_data.curScene.name + " 结束");
	m_data.s.curSceneFin = true;
}

/**
 * 添加模块
 * @param module
 *   模块数据
 */
function addModule(module) {
	var name = module.name;
	m_data.m.modules[name] = module;
}

/**
 * 获得当前模块
 */
function currentModule() {
	return m_data.curModule;
}

/**
 * 获得共享数据上下文
 */
function getSharecontext() {
	return m_data.shareContext;
}

/**
 * 删除指定的渲染函数. 这个函数将依据添加的名称来进行查找.
 * @param name
 *   String, 模块名称
 */
function delRenderFunc(name) {
	delete m_data.renderFuncs[name];
}


/**
 *给每个module设置存储动态参数
 * @param mName
 *	 String,   模块名称
 *   或Number,  非负数。0表示当前模块，1表示下一个模块，以此类推
 *   或Array,	可以是String或Integer的集合，。系统逐个判断每个元素，确定哪些模块进行操作
 *   或Function, 输入（模块名称，模块类型），输出true或false，系统将参数设置到输出位true的模块中
 * @param key
 *   string,	 存入模块的数据的键
 * @param value
 *   任意类型,   存入模块的数据的值，key与value为键值对
*/
function setConfig(mName,key,value){
	if((typeof mName !== 'string')&&(typeof mName !== 'number')&&(typeof mName !== 'object')&&(typeof mName !== 'function')){
		console.error('It is not a string,number,array or function');
		return;
	}

	if(typeof key !== 'string'){
		console.error('It is not a string');
		return;
	}

	//判断mName的类型，选择处理方法

	if(typeof mName == 'string'){
		m_data.judgeConfig(mName,key,value);
	}else if(typeof mName == 'number'){
		m_data.judgeConfig(modulesOrder[curModuleIdx + mName].name,key,value);
	}else if(typeof mName == 'object'){
		var mNameIdx = 0;
		for(mNameIdx = 0;mNameIdx < mName.length;mNameIdx++){
			if((typeof mName[mNameIdx] !== 'string')&&(typeof mName[mNameIdx] !== 'number')){
				console.error('An element is not a string or integer in the array at least');
				return;
			}

		for(mNameIdx = 0;mNameIdx < mName.length;mNameIdx++){
			if(typeof mName[mNameIdx] == 'string'){
				m_data.judgeConfig(mName[mNameIdx],key,value);
			}else if(typeof mName[mNameIdx] == 'number'){
				m_data.judgeConfig(modulesOrder[curModuleIdx + mName[mNameIdx]].name,key,value);
			}
		}
		}
	}else if(typeof mName == 'function'){
		for(var index in m_data.m.modules){
			if(mName(m_data.m.modules[index])){
				m_data.judgeConfig(index,key,value);
			}
		}
	}
}


/**
 * 注册监听的事件
 * @param event  String|Array(String)
 *  想要接受的事件类型
 * @param callback  Function(event, argv)
 *  回调函数
 */
function subscribeEvent(event, callback) {
	m_data.e.subscribe(event, callback);
}

/**
 * 发布事件
 * @param event  String
 *   事件名称
 * @param argv  任意
 *   其它附属参数
 */
function releaseEvent(event, argv) {
	m_data.e.release(event, argv);
}
